/**
  ******************************************************************************
  * @file    srvr.h
  * @author  Waveshare Team
  * @version V1.0.0
  * @date    23-January-2018
  * @brief   ESP8266 WiFi server.
  *          This file provides firmware functions:
  *           + Sending web page of the tool to a client's browser
  *           + Uploading images from client part by part
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
//#include <ESP8266WiFi.h>// ESP8266 and WiFi classes
#include <WiFi.h>
#include <NetworkClient.h>
#include <WebServer.h> 

#include <WiFiAP.h>
#include "driver/rtc_io.h"

#include "buff.h" // POST request data accumulator
#include "epd.h"  // e-Paper driver

#include "web_file.h"
#include "scripts.h" // JavaScript code
#include "css.h"     // Cascading Style Sheets
#include "html.h"    // HTML page of the tool
#include "get_pwr_val.h" // vbat adc

#define ARR_LENGTH(array) (sizeof(array) / sizeof(array[0]))

#define max_connect_count 5

/* STD set================================================================== */
/* SSID and password of your WiFi net ----------------------------------------*/
const char *ssid = "personal-code"; //"your ssid";
const char *password = "old2DZ1M";   //"your password";

/* Static IP address Settings ------------------------------------------------*/
IPAddress staticIP(192, 168, 0, 199);
IPAddress gateway(192, 168, 0, 1);
IPAddress subnet(255, 255, 255, 0);
IPAddress dns(223, 5, 5, 5);
/* Server and IP address ------------------------------------------------------*/
WiFiServer server(80); // Wifi server exemplar using port 80
IPAddress myIP;        // IP address in your local wifi net

/* The 'index' page flag ------------------------------------------------------*/
bool isIndexPage = true; // true : GET  request, client needs 'index' page;
// false: POST request, server sends empty page.


/** ap set =========================== */
/* ap ssid */
const char *ap_ssid = "EPD Server s2";
/* ap pwd */
const char *ap_password = "333333333";
/* ap service port */
WebServer esp32_server(80);

void handleUserRequet() {
    esp32_server.send(404, "text/plain", "404 Not Found");  // 如果在SD卡无法找到用户访问的资源，则回复404 (Not Found)
}

void webRoot()
{
    float pwr = get_pwr_vol();
    esp32_server.send(200, "text/html", root_html(myIP, pwr));
}

void Srvr__setup()
{

    IPAddress local_IP(192, 168, 0, 1);
    
    WiFi.softAPConfig(local_IP,gateway,subnet);
    if (!WiFi.softAP(ap_ssid, ap_password)) {
        log_e("Soft AP creation failed.");
        while (1);
    }
    myIP = WiFi.softAPIP();
    Serial.print("AP IP address: ");
    Serial.println(myIP);

    esp32_server.onNotFound(handleUserRequet);      // 告知系统如何处理用户请求
    esp32_server.on("/", webRoot);
    esp32_server.on("/styles.css", [](){esp32_server.send(200, "text/css", root_css());});
    esp32_server.on("/scriptA.js", [](){esp32_server.send(200, "text/javascript", root_script_a());});
    esp32_server.on("/scriptB.js", [](){esp32_server.send(200, "text/javascript", root_script_b());});
    esp32_server.on("/scriptC.js", [](){esp32_server.send(200, "text/javascript", root_script_c());});
    esp32_server.on("/scriptD.js", [](){esp32_server.send(200, "text/javascript", root_script_d());});
    // ------[1]------------------------------------
    esp32_server.on("/EPD", HTTP_POST, [](){
        // epd size
        // ind: char code
        String indParam = esp32_server.arg("ind"); // index
        const char ind = indParam[0];
        Serial.print("\r\nEPD\r\n");
        Serial.print("ind: ");
        Serial.print(indParam);
        Serial.print("\r\nchar ind:");
        Serial.print(ind);
        Serial.print("\r\nind - a: ");
        Serial.print((int)ind - (int)'a');
        EPD_dispIndex = (int)ind - (int)'a'; // 7 // (int)ind - (int)'a'; // 例如 m(109) - a(97) = 12 => 对应 "2.9 inch d"
        if(EPD_dispIndex < 0)
            EPD_dispIndex = (int)ind - (int)'A' + 26;
        // 27
        // for(int index = 0; index < 27; index++) {
        //     if (EPD_dispMass[index].id == ind) {
        //         // Getting of e-Paper's type
        //         EPD_dispIndex = index; // 写进 display index
        //     }
        // }
        // Print log message: initialization of e-Paper (e-Paper's type)
        Serial.printf("\r\nEPD %s", EPD_dispMass[EPD_dispIndex].title);
        // Initialization
        EPD_dispInit();
        esp32_server.send(200, "text/html", "OK!");
    });
    // ------[2]------------------------------------
    esp32_server.on("/DATA", HTTP_POST, [](){
        String d = esp32_server.arg("d"); // epd data
        // d
        Serial.print("\r\nparams d:");
        Serial.print(d);
        Serial.print("\r\n");
        Buff__bufInd = 0;
        int ind = 0;
        while(d[ind] != '\0') {
            Buff__bufArr[Buff__bufInd++] = (byte)d[ind++];
        }
        // Image loading
        // Print log message: image loading
        Serial.print("LOAD");
        // Load data into the e-Paper
        // if there is loading function for current channel (black or red)
        if (EPD_dispLoad != 0)
            EPD_dispLoad();
        esp32_server.send(200, "text/html", "OK!");
    });
    // ------[3]-----------------------------------------
    esp32_server.on("/NEXT", HTTP_POST,[](){
        // next data
        // Print log message: next data channel
        Serial.print("NEXT");
        // Instruction code for for writting data into
        // e-Paper's memory
        int code = EPD_dispMass[EPD_dispIndex].next;
        if(EPD_dispIndex == 34)
        {
            if(flag == 0)
                code = 0x26;
            else
                code = 0x13;
        }
        // If the instruction code isn't '-1', then...
        if (code != -1) {
            // Print log message: instruction code
            Serial.printf(" %x", code);

            // Do the selection of the next data channel
            EPD_SendCommand(code);
            delay(2);
        }
        // Setup the function for loading choosen channel's data
        EPD_dispLoad = EPD_dispMass[EPD_dispIndex].chRd;
        esp32_server.send(200, "text/html", "OK!");
    });
    // --------[4]------------------------------------------
    esp32_server.on("/SHOW",HTTP_POST, [](){
        // show epd
        // Show results and Sleep
        EPD_dispMass[EPD_dispIndex].show();
        //Print log message: show
        Serial.print("\r\nSHOW");
        esp32_server.send(200, "text/html", "OK!");
    });

    esp32_server.begin();

    Serial.println("Server started");
}

/* Server initialization -------------------------------------------------------*/
void Srvr__setup_STA()
{
    Serial.println();
    Serial.println();
    Serial.print("Connecting to ");
    Serial.println(ssid);

    if (WiFi.config(staticIP, gateway, subnet, dns, dns) == false) {
      Serial.println("Configuration failed.");
    }

    // Applying SSID and password
    WiFi.begin(ssid, password);

    int times = 0;

    // Waiting the connection to a router
    while (WiFi.status() != WL_CONNECTED && times < max_connect_count) {
        delay(500);
        times ++;
        Serial.print("connect times:");
        Serial.print(times);
        Serial.print("\n");
    }
    if (WiFi.status() == WL_CONNECTED) {
        // Connection is complete
        Serial.println("");
        Serial.println("WiFi connected");

        // Start the server
        server.begin();
        Serial.println("Server started");

        // Show obtained IP address in local Wifi net
        Serial.println(myIP = WiFi.localIP());
    } else if (times >= max_connect_count) {
        // WiFi.end();
        Serial.println("connect timeout...");
    } else {
        Serial.println("other error");
    }
}

/* Sending a script to the client's browser ------------------------------------*/
bool Srvr__file(WiFiClient client, int fileIndex, char *fileName)
{
    // Print log message: sending of script file
    Serial.print(fileName);

    // Sent to the 'client' the header describing the type of data.
    client.print(fileIndex == 0
                 ? "HTTP/1.1 200 OK\r\nContent-Type: text/css\r\n\r\n"
                 : "HTTP/1.1 200 OK\r\nContent-Type: text/javascript\r\n\r\n");

    // Choose the index of script
    // (ESP8266 can't to send all of code by one file
    // and needs split it on a few parts)
    switch (fileIndex) {
        case 0:
            sendCSS(client);
            break;
        case 1:
            sendJS_A(client);
            break;
        case 2:
            sendJS_B(client);
            break;
        case 3:
            sendJS_C(client);
            break;
        case 4:
            sendJS_D(client);
            break;
    }

    client.print("\r\n");
    delay(1);

    // Print log message: the end of request processing
    Serial.println(">>>");

    return true;
}

/* The server state observation loop -------------------------------------------*/
bool Srvr__loop()
{
    // Looking for a client trying to connect to the server
    WiFiClient client = server.available();
    int16_t label = 0;
    int16_t fale = 1000;

    // Exit if there is no any clients
    if (!client)
        return false;

    // Print log message: the start of request processing
    Serial.print("<<<");

    // Waiting the client is ready to send data
    while (!client.available())
    {
        delay(1); 
        label++;
        if(label > fale)
        {
            label = fale + 1;
            if(!server.available())
                return false;
        }
    }

    // Set buffer's index to zero
    // It means the buffer is empty initially
    Buff__bufInd = 0;

    // While the stream of 'client' has some data do...
    while (client.available()) {
        // Read a character from 'client'
        int q = client.read();

        // Save it in the buffer and increment its index
        Buff__bufArr[Buff__bufInd++] = (byte)q;

        // If the carachter means the end of line, then...
        if ((q == 10) || (q == 13)) { //
            // Clean the buffer
            Buff__bufInd = 0;
            continue;
        }

        // Requests of files
        if (Buff__bufInd >= 11) {
            if (Buff__signature(Buff__bufInd - 11, "/styles.css"))
                return Srvr__file(client, 0, "styles.css");

            if (Buff__signature(Buff__bufInd - 11, "/scriptA.js"))
                return Srvr__file(client, 1, "scriptA.js");

            if (Buff__signature(Buff__bufInd - 11, "/scriptB.js"))
                return Srvr__file(client, 2, "scriptB.js");

            if (Buff__signature(Buff__bufInd - 11, "/scriptC.js"))
                return Srvr__file(client, 3, "scriptC.js");

            if (Buff__signature(Buff__bufInd - 11, "/scriptD.js"))
                return Srvr__file(client, 4, "scriptD.js");
        }

        // If the buffer's length is larger, than 4 (length of command's name), then...
        if (Buff__bufInd > 4) {
            // It is probably POST request, no need to send the 'index' page
            isIndexPage = false;

            // e-Paper driver initialization
            if (Buff__signature(Buff__bufInd - 4, "EPD")) {
                Serial.print("\r\nEPD\r\n");
                // Getting of e-Paper's type
                EPD_dispIndex = (int)Buff__bufArr[Buff__bufInd - 1] - (int)'a'; // 例如 m(109) - a(97) = 12 => 对应 "2.9 inch d"
                if(EPD_dispIndex < 0)
                  EPD_dispIndex = (int)Buff__bufArr[Buff__bufInd - 1] - (int)'A' + 26;
                // Print log message: initialization of e-Paper (e-Paper's type)
                Serial.printf("EPD %s", EPD_dispMass[EPD_dispIndex].title);
                // Initialization
                EPD_dispInit();
                //client.print("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");
                break;
            }

            // Image loading
            if (Buff__signature(Buff__bufInd - 4, "LOAD")) {
                // Print log message: image loading
                Serial.print("LOAD");

                // Load data into the e-Paper
                // if there is loading function for current channel (black or red)
                if (EPD_dispLoad != 0)
                    EPD_dispLoad();
                //client.print("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");
                break;
            }

            // Select the next data channel
            if (Buff__signature(Buff__bufInd - 4, "NEXT")) {
                // Print log message: next data channel
                Serial.print("NEXT");

                // Instruction code for for writting data into
                // e-Paper's memory
                int code = EPD_dispMass[EPD_dispIndex].next;
                if(EPD_dispIndex == 34)
                {
                    if(flag == 0)
                        code = 0x26;
                    else
                        code = 0x13;
                }

                // If the instruction code isn't '-1', then...
                if (code != -1) {
                    // Print log message: instruction code
                    Serial.printf(" %x", code);

                    // Do the selection of the next data channel
                    EPD_SendCommand(code);
                    delay(2);
                }

                // Setup the function for loading choosen channel's data
                EPD_dispLoad = EPD_dispMass[EPD_dispIndex].chRd;
                //client.print("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");
                break;
            }

            // If the loading is complete, then...
            if (Buff__signature(Buff__bufInd - 4, "SHOW")) {
                // Show results and Sleep
                EPD_dispMass[EPD_dispIndex].show();

                //Print log message: show
                Serial.print("\r\nSHOW");
                //client.print("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");
                break;
            }

            // If the routine reaches this code,
            // it means the there is no known commands,
            // the server has to send the 'index' page
            isIndexPage = true;
        }
    }

    // Clear data stream of the 'client'
    client.flush();

    // Sent to the 'client' the header describing the type of data.
    // In this case 'Content-Type' is 'text/html'
    client.print("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");

    // Send the 'index' page if it's needed
    if (isIndexPage) {
        float pwr = get_pwr_vol();
        sendHtml(client, myIP, pwr);
    }
    else {
        client.print("Ok!");
    }

    client.print("\r\n");
    delay(1);

    // Print log message: the end of request processing
    Serial.println(">>>");
    return true;
}

void Ap_loop() {
  esp32_server.handleClient();
  delay(10);
}

void esp_deep_sleep() {
  //Go to sleep now
  Serial.println("Going to sleep now");
  esp_deep_sleep_start();
  // Serial.println("This will never be printed");
}